﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataObject.Database;

namespace TreasureJunk.Bl
{
    public class ReportImpl : BaseImpl
    {
        private static ReportImpl _instance;
        public static ReportImpl Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new ReportImpl();
                }
                return _instance;
            }
        }

        private string GetRouteCode(int routeNumber, string subCode)
        {
            return routeNumber + (string.IsNullOrEmpty(subCode) ? string.Empty : ('-' + subCode));
        }


        public object LoadAnalytics(DateTime fromDate, DateTime toDate, ChartCategory chartCate, int? pageSize, int? pageNum)
        {
            List<object> data = new List<object>();

            try
            {
                using (OBSDataContext db = new OBSDataContext(base.connectionString))
                {
                    fromDate = fromDate.Date;
                    toDate = toDate.Date.AddDays(1);
                    var query = from x in db.Reservations
                                where x.CheckInDate >= fromDate && x.CheckInDate < toDate
                                && x.Status == 0
                                select x;

                    ChartData<ChartDatum<DateTime>> chartData = new ChartData<ChartDatum<DateTime>>("Bookings summary");
                    chartData.Data = query.GroupBy(x => x.CheckInDate.Date).Select(x => new ChartDatum<DateTime> { category = x.Key, value = x.Count(), value1 = x.Sum(y => y.NumOfPax) }).OrderBy(x => x.category).ToList();

                    data.Add(chartData);

                    int rowCount;
                    var barChartData = LoadByCategory(chartCate, query, db, pageSize, pageNum, out rowCount);
                    data.Add(barChartData);

                    data.Add(rowCount > 10);
                }

                return data;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public object LoadAnalyticsByCategory(DateTime fromDate, DateTime toDate, ChartCategory chartCate, int? pageSize, int? pageNum)
        {
            List<object> data = new List<object>();

            try
            {
                using (OBSDataContext db = new OBSDataContext(base.connectionString))
                {
                    fromDate = fromDate.Date;
                    toDate = toDate.Date.AddDays(1);
                    var query = from x in db.Reservations
                                where x.CheckInDate >= fromDate && x.CheckInDate < toDate
                                && x.Status == 0
                                select x;

                    int rowCount;
                    var barChartData = LoadByCategory(chartCate, query, db, pageSize, pageNum, out rowCount);
                    data.Add(barChartData);

                    data.Add(rowCount > 10);
                }

                return data;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public object LoadByCategory(ChartCategory chartCate, IQueryable<Reservation> query, OBSDataContext db, int? pageSize, int? pageNum, out int rowCount)
        {
            var barChartData = new ChartData<ChartDatum<string>>(chartCate.ToString());
            switch (chartCate)
            {
                case ChartCategory.Cabins:
                    var guids = query.Select(x => x.ReservationID).ToList();
                    var query11 = from x in db.ReservationDetails
                                 join z in db.CabinEntities on x.CabinID equals z.CabinID
                                 where x.Status == 1 && guids.Contains(x.ReservationID)
                                 select new { z, x };
                    rowCount = query11.Count();
                    barChartData.Data = query11.GroupBy(z => z.z.CabinNumber).Select(x => new ChartDatum<string> { category = x.Key, value = x.Sum(z => z.x.NumOfPeople) }).ToList();
                    break;
                case ChartCategory.Country:
                    var query1 = from x in query
                                 join y in db.Guests on x.GuestID equals y.GuestID into group1
                                 from g1 in group1.DefaultIfEmpty()
                                 join z in db.ParameterEntities on g1.CountryID equals z.ParamID into group2
                                 from g2 in group2.DefaultIfEmpty()
                                 select new { g2, x };
                    var query101 = query1.GroupBy(x => x.g2.Value).Select(x => new ChartDatum<string> { category = x.Key, value = x.Sum(z => z.x.NumOfPax) });
                    rowCount = query101.Count();

                    if (pageNum.HasValue && pageSize.HasValue)
                        barChartData.Data = query101.PageIQuery(pageNum.Value, pageSize.Value).OrderByDescending(x => x.value).ToList();
                    else
                        barChartData.Data = query101.OrderByDescending(x => x.value).ToList();
                    break;
                case ChartCategory.CustomerType:
                    var query2 = from x in query
                                 join y in db.Guests on x.GuestID equals y.GuestID into group1
                                 from g1 in group1.DefaultIfEmpty()
                                 select new { g1, x };
                    var query201 = query2.GroupBy(x => x.g1.GuestType).Select(x => new ChartDatum<string> { category = x.Key == 0 ? "Agent" : "WI", value = x.Sum(z => z.x.NumOfPax) });
                    rowCount = query201.Count();
                    if (pageNum.HasValue && pageSize.HasValue)
                        barChartData.Data = query201.PageIQuery(pageNum.Value, pageSize.Value).OrderByDescending(x => x.value).ToList();
                    else
                        barChartData.Data = query201.OrderByDescending(x => x.value).ToList();
                    break;
                case ChartCategory.Customer:
                    query2 = from x in query
                             join y in db.Guests on x.GuestID equals y.GuestID into group1
                             from g1 in group1.DefaultIfEmpty()
                             select new { g1, x };
                    query201 = query2.GroupBy(x => new { x.g1.FirstName, x.g1.Lastname }).Select(x => new ChartDatum<string> { category = x.Key.FirstName + ' ' + x.Key.Lastname, value = x.Sum(z => z.x.NumOfPax) });
                    rowCount = query201.Count();
                    if (pageNum.HasValue && pageSize.HasValue)
                        barChartData.Data = query201.PageIQuery(pageNum.Value, pageSize.Value).OrderByDescending(x => x.value).ToList();
                    else
                        barChartData.Data = query201.OrderByDescending(x => x.value).ToList();
                    break;
                default:
                    rowCount = 0;
                    break;
            }
            return barChartData;
        }
    }

    public class ChartData<T>
    {
        public string Title { get; set; }
        public List<T> Data { get; set; }

        public ChartData()
        {
            Data = new List<T>();
        }

        public ChartData(string title)
            : this()
        {
            this.Title = title;
        }
    }
    
    public class ChartDatum<T>
    {
        public T category { get; set; }
        public decimal value { get; set; }
        public decimal value1 { get; set; }
    }

    public enum ChartCategory
    {
        Cabins,
        Country,
        CustomerType,
        Customer
    }
}
